home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / unix / src / _main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-21  |  11.4 KB  |  468 lines

  1. #include "amiga.h"
  2. #include "signals.h"
  3. #include "fifofd.h"
  4. #include "timers.h"
  5. #include "amigados.h"
  6. #include <exec/execbase.h>
  7. #include <dos/var.h>
  8. #include <workbench/startup.h>
  9. #include <proto/timer.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <sys/time.h>
  14. #include <pwd.h>
  15.  
  16. struct Process *_us;
  17. struct timeinfo *_odd_timer;
  18. ULONG _odd_sig;
  19. long _startup_time;
  20. long _stack_size;
  21. struct Device *TimerBase;
  22.  
  23. static char *empty_env = 0;    /* A default empty environment */
  24. char **environ;            /* Unix style environment variable list */
  25. char *_system_name;
  26.  
  27. extern struct ExecBase *SysBase;
  28. extern struct passwd _amiga_user;
  29. extern main(int argc, char **argv, char **envp);
  30.  
  31. static void nomem(void)
  32. {
  33.   _fail("No memory");
  34. }
  35.  
  36. static void *_xmalloc(unsigned n)
  37. {
  38.     void *p = malloc(n);
  39.  
  40.     if (!p) nomem();
  41.  
  42.     return p;
  43. }
  44.  
  45. static void *_xrealloc(void *p, unsigned n)
  46. {
  47.     void *p2 = realloc(p, n);
  48.  
  49.     if (!p2) nomem();
  50.  
  51.     return p2;
  52. }
  53.  
  54. static char *safe_copystr(char *str)
  55. {
  56.     char *new;
  57.  
  58.     if (!str) str = "";
  59.     new = malloc(strlen(str) + 1);
  60.     if (!new) return 0;
  61.     return strcpy(new, str);
  62. }
  63.  
  64. static char *copystr(char *str)
  65. {
  66.     char *new = safe_copystr(str);
  67.  
  68.     if (!new) nomem();
  69.  
  70.     return new;
  71. }
  72.  
  73. void make_environ(void)
  74. /* Effect: Builds a UNIX style environ variable from the AmigaDOS environment.
  75. */
  76. {
  77.     int env_count = 0;
  78.     long env_len = 0;
  79.     struct LocalVar *scan_env;
  80.     char **new_environ, *env_text;
  81.  
  82.     for (scan_env = (struct LocalVar *)_us->pr_LocalVars.mlh_Head;
  83.      scan_env->lv_Node.ln_Succ;
  84.      scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
  85.     if (scan_env->lv_Node.ln_Type == LV_VAR &&
  86.         !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
  87.     {
  88.         /* We only handle local text variables */
  89.         env_count++;
  90.         env_len += 2 + strlen(scan_env->lv_Node.ln_Name) + scan_env->lv_Len;
  91.     }
  92.  
  93.     new_environ = environ = (char **)_xmalloc(sizeof(char *) * (1 + env_count) +
  94.                           env_len);
  95.     env_text = (char *)(environ + (1 + env_count));
  96.     if (!environ) environ = &empty_env;
  97.     else
  98.     {
  99.     for (scan_env = (struct LocalVar *)_us->pr_LocalVars.mlh_Head;
  100.          scan_env->lv_Node.ln_Succ;
  101.          scan_env = (struct LocalVar *)scan_env->lv_Node.ln_Succ)
  102.         if (scan_env->lv_Node.ln_Type == LV_VAR &&
  103.         !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR)))
  104.         {
  105.         /* We only handle local text variables */
  106.         char *env_name = scan_env->lv_Node.ln_Name;
  107.         int env_len = scan_env->lv_Len;
  108.  
  109.         *new_environ++ = env_text;
  110.         while (*env_name) *env_text++ = *env_name++;
  111.         *env_text++ = '=';
  112.         env_name = scan_env->lv_Value;
  113.         while (env_len--) *env_text++ = *env_name++;
  114.         *env_text++ = '\0';
  115.         }
  116.     *new_environ = 0;
  117.     }
  118. }
  119.  
  120. /* _main routine.
  121.    Hides the differences between wb & cli.
  122.    Provides a unix-like environment (including coomand-line parsing &
  123.    wildcard expansion)
  124. */
  125.  
  126. #define DEFPATLEN 256
  127. #define NAMELEN 1024
  128.  
  129. struct args
  130. {
  131.     int size;
  132.     int argc;
  133.     char **argv;
  134. };
  135.  
  136. static void make_argv(struct args *args, int argc)
  137. {
  138.     args->size = argc;
  139.     args->argc = 0;
  140.     args->argv = _xmalloc(sizeof(char *) * argc);
  141. }
  142.  
  143. static int safe_add_arg(struct args *args, char *argument, int copy)
  144. {
  145.     char *arg_copy;
  146.  
  147.     if (copy) arg_copy = safe_copystr(argument);
  148.     else arg_copy = argument;
  149.     if (!arg_copy) return 0;
  150.  
  151.     if (args->argc >= args->size)
  152.     {
  153.     /* Make argv bigger */
  154.     if (args->size * 2 < args->size + 16) args->size += 16;
  155.     else args->size *= 2;
  156.     args->argv = realloc(args->argv, sizeof(char *) * args->size);
  157.     if (!args->argv) return 0;
  158.     }
  159.     args->argv[args->argc++] = arg_copy;
  160.     return 1;
  161. }
  162.  
  163. static void add_arg(struct args *args, char *argument, int copy)
  164. {
  165.     if (!safe_add_arg(args, argument, copy)) nomem();
  166. }
  167.  
  168. static void concat_args(struct args *args, struct args *add)
  169. {
  170.     if (args->argc + add->argc > args->size)
  171.     {
  172.     args->size = (args->argc + add->argc) * 2;
  173.     args->argv = _xrealloc(args->argv, sizeof(char *) * args->size);
  174.     }
  175.     memcpy(args->argv + args->argc, add->argv, add->argc * sizeof(char *));
  176.     args->argc += add->argc;
  177.     free(add->argv);
  178. }
  179.  
  180. typedef enum { quote_none, quote_single, quote_double } quote_type;
  181. typedef enum { extract_normal, extract_test, extract_pattern } extract_type;
  182.  
  183. static void extract(char *buf, char *start, char *end,
  184.             quote_type type, extract_type extract)
  185. {
  186.   char *res = buf;
  187.  
  188.   switch (type)
  189.     {
  190.     case quote_single:
  191.       if (extract != extract_test)
  192.     {
  193.       buf[end - start] = '\0';
  194.       memcpy(buf, start, end - start);
  195.     }
  196.       else strcpy(buf, "a");    /* Things in quotes are never patterns */
  197.       break;
  198.  
  199.     case quote_none:
  200.       while (start < end)
  201.     {
  202.       if (start[0] == '\\' && start[1])
  203.         {
  204.           start += 2;
  205.           /* Wildcard are escaped */
  206.           if (extract == extract_test) *res++ = 'a';
  207.           else if (extract == extract_pattern)
  208.         switch (start[-1])
  209.           {
  210.           case '?': case '#': case '(': case ')': case '|': case '[':
  211.           case ']': case '~': case '%': case '*': case '\'':
  212.             *res++ = '\'';
  213.           default:
  214.             *res++ = start[-1];
  215.             break;
  216.           }
  217.           else *res++ = start[-1];
  218.         }
  219.       else *res++ = *start++;
  220.     }
  221.       *res++ = '\0';
  222.       break;
  223.  
  224.     case quote_double:
  225.       while (start < end)
  226.     {
  227.       if (start[0] == '*' && start[1])
  228.         {
  229.           start += 2;
  230.           switch (start[-1])
  231.         {
  232.         case 'n': *res++ = '\n'; break;
  233.         case 'e': *res++ = '\x1b'; break;
  234.         default: *res++ = start[-1]; break;
  235.         }
  236.         }
  237.       else *res++ = *start++;
  238.     }
  239.       *res++ = '\0';
  240.       break;
  241.     }
  242. }
  243.  
  244. void _main(char *line)
  245. /* Effect: Call unix_main with wildcards in argc & argv expanded (like unix)
  246.      Also, do some early amiga initialisation for emacs.
  247. */
  248. {
  249.   struct args args, wildargs;
  250.   char *pattern, *arg_start, *arg_end, *arg;
  251.   quote_type arg_quoted;
  252.   long patlen = DEFPATLEN;
  253.   struct AnchorPath *anchor;
  254.   struct timeval now;
  255.  
  256.   if (SysBase->LibNode.lib_Version < 37) XCEXIT(20);
  257.  
  258.   stdin->_file = 0;
  259.   stdin->_flag = _IOREAD;
  260.   stdout->_file = 1;
  261.   stdout->_flag = _IOWRT;
  262.   stderr->_file = 2;
  263.   stderr->_flag = _IORW | _IONBF;
  264.  
  265.   _us = (struct Process *)FindTask(0);
  266.   _odd_timer = _alloc_timer();
  267.   if (!_odd_timer) _fail("Failed to create timer");
  268.   _odd_sig = _timer_sig(_odd_timer);
  269.   TimerBase = _odd_timer->io->tr_node.io_Device;
  270.   GetSysTime(&now);
  271.   _startup_time = now.tv_secs;
  272.  
  273.   /* These use _startup_time, so must be here */
  274.   _init_fifo();
  275.   _init_signals();
  276.  
  277.   if (_us->pr_CLI) _stack_size = ((struct CommandLineInterface *)BADDR(_us->pr_CLI))->cli_DefaultStack << 2;
  278.   else _stack_size = _us->pr_StackSize;
  279.  
  280.   /* Make unix-like argc, argv (expand wildcards) */
  281.   if (!line[0])            /* Workbench, create argc & argv from files passed */
  282.     {
  283.       extern struct WBStartup *WBenchMsg;
  284.       int i;
  285.       BPTR nilin = Open("NIL:",MODE_NEWFILE);
  286.       BPTR nilout = Open("NIL:",MODE_NEWFILE);
  287.       BPTR nilerr = Open("NIL:",MODE_NEWFILE);
  288.  
  289.       /* Initialise I/O. Nothing is available */
  290.       if (!nilin || !nilout || !nilerr)
  291.     {
  292.       if (nilin) Close(nilin);
  293.       if (nilout) Close(nilout);
  294.       if (nilerr) Close(nilerr);
  295.       nomem();
  296.     }
  297.       _init_unixio(nilin, TRUE, nilout, TRUE, nilerr, TRUE);
  298.  
  299.       /* Make argc, argv from Workbench parameters */
  300.       make_argv(&args, WBenchMsg->sm_NumArgs);
  301.  
  302.       for (i = 0; i < WBenchMsg->sm_NumArgs; i++)
  303.     {
  304.       char filename[256];
  305.  
  306.       if (NameFromLock(WBenchMsg->sm_ArgList[i].wa_Lock, filename, 256))
  307.         {
  308.           AddPart(filename, WBenchMsg->sm_ArgList[i].wa_Name, 256);
  309.           add_arg(&args, filename, TRUE);
  310.         }
  311.       /* else A parameter was lost, cry, cry, cry */
  312.     }
  313.     }
  314.   else                /* From CLI expand wildcards (with unix-like command line parsing) */
  315.     {
  316.       int close_error;
  317.       BPTR in, out, error;
  318.  
  319.       /* Initialise I/O. Copy CLI info */
  320.       in = Input();
  321.       out = Output();
  322.       close_error = FALSE;
  323.       if ((error = _us->pr_CES) == 0)
  324.     {
  325.       close_error = TRUE;
  326.       if ((error = Open("*", MODE_OLDFILE)) == 0)
  327.         if ((error = Open("NIL:", MODE_OLDFILE)) == 0) nomem();
  328.     }
  329.       _init_unixio(in, FALSE, out, FALSE, error, close_error);
  330.  
  331.       make_argv(&args, 1);
  332.  
  333.       anchor = _xmalloc(sizeof(struct AnchorPath) + NAMELEN);
  334.       anchor->ap_Strlen = NAMELEN;
  335.       pattern = _xmalloc(DEFPATLEN);
  336.       while (1)
  337.     {
  338.       long new_patlen;
  339.       int wild;
  340.  
  341.       /* Skip white space */
  342.       while (isspace(*line)) line++;
  343.       if (!*line) break;    /* End of command line */
  344.  
  345.       /* Extract next word */
  346.       /* Words in double quotes are handled AmigaDOS style
  347.          (+ filename expansion) */
  348.       if (*line == '"')
  349.         {
  350.           line++;
  351.           arg_start = line;
  352.           /* Find end of word */
  353.           while (*line && *line != '"')
  354.         {
  355.           /* * is an escape character inside double quotes
  356.              (AmigaDOS compatibility) */
  357.           if ((*line == '*') && line[1]) line++;
  358.           line++;
  359.         }
  360.           arg_end = line;
  361.           if (*line == '"') line++;
  362.           arg_quoted = quote_double;
  363.         }
  364.       /* Words in single quotes are handled unix style */
  365.       else if (*line == '\'')
  366.         {
  367.           line++;
  368.           arg_start = line;
  369.           /* Find end of word */
  370.           while (*line && *line != '\'') line++;
  371.           arg_end = line;
  372.           if (*line == '\'') line++;
  373.           arg_quoted = quote_single;
  374.         }
  375.       /* Unquoted words are handled unix style */
  376.       else            /* Plain word */
  377.         {
  378.           arg_start = line;
  379.           /* Find end of word */
  380.           while (*line && !isspace(*line))
  381.         {
  382.           if (*line == '\\' && line[1]) line++;
  383.           line++;
  384.         }
  385.           arg_end = line;
  386.           arg_quoted = quote_none;
  387.         }
  388.       arg = _xmalloc(arg_end - arg_start + 1);
  389.       if (args.argc == 0)    /* Command name is left untouched */
  390.         {
  391.           strncpy(arg, arg_start, arg_end - arg_start);
  392.           arg[arg_end - arg_start] = 0;
  393.           add_arg(&args, arg, FALSE);
  394.         }
  395.       else
  396.         {
  397.           new_patlen = (arg_end - arg_start) * 2 + 16;
  398.           if (new_patlen > patlen)
  399.         {
  400.           free(pattern);
  401.           pattern = _xmalloc(new_patlen);
  402.           patlen = new_patlen;
  403.         }
  404.           extract(arg, arg_start, arg_end, arg_quoted, extract_test);
  405.           wild = ParsePattern(arg, pattern, patlen);
  406.           if (wild < 0)
  407.         {
  408.           *arg_end = 0;
  409.           _fail("Invalid wildcard %s", arg_start);
  410.         }
  411.           if (!wild)
  412.         {
  413.           extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
  414.           add_arg(&args, arg, FALSE);
  415.         }
  416.           else
  417.         {
  418.           int none = TRUE;
  419.           long error;
  420.  
  421.           anchor->ap_Flags = anchor->ap_Reserved = anchor->ap_BreakBits = 0;
  422.           extract(arg, arg_start, arg_end, arg_quoted, extract_pattern);
  423.           make_argv(&wildargs, 16);
  424.           error = MatchFirst(arg, anchor);
  425.           while (!error)
  426.             {
  427.               none = FALSE;
  428.               if (!safe_add_arg(&wildargs, anchor->ap_Buf, TRUE))
  429.             {
  430.               error = ERROR_NO_FREE_STORE;
  431.               break;
  432.             }
  433.               error = MatchNext(anchor);
  434.             }
  435.           MatchEnd(anchor);
  436.           if (error != ERROR_NO_MORE_ENTRIES)
  437.               _fail("Error expanding arguments");
  438.           if (none)
  439.             {
  440.               extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
  441.               add_arg(&args, arg, FALSE);
  442.             }
  443.           else
  444.             {
  445.               tqsort(wildargs.argv, wildargs.argc);
  446.               concat_args(&args, &wildargs);
  447.               free(arg);
  448.             }
  449.         }
  450.         }
  451.     }
  452.       free(pattern);
  453.       free(anchor);
  454.     }
  455.  
  456.   make_environ();
  457.  
  458.   if (!(_amiga_user.pw_name = getenv("USER"))) _amiga_user.pw_name = "user";
  459.   if (!(_amiga_user.pw_gecos = getenv("USERNAME")))
  460.     _amiga_user.pw_gecos = _amiga_user.pw_name;
  461.   if (!(_amiga_user.pw_dir = getenv("HOME"))) _amiga_user.pw_dir = "s:";
  462.   if (!(_amiga_user.pw_shell = getenv("SHELL"))) _amiga_user.pw_shell = "bin:sh";
  463.   if (!(_system_name = getenv("HOSTNAME"))) _system_name = "amiga";
  464.     
  465.   main(args.argc, args.argv, environ);
  466.   exit(0);
  467. }
  468.